﻿using System;
using System.Collections.Generic;
using BlawkayEngine;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Net;

namespace BlawkayHockey
{
    public static class Networking
    {
        public enum SessionProperty { GameMode, SkillLevel }
        public enum GameMode { Practice, Normal, FirstTo }
        public enum SkillLevel { Beginner, Advanced }

        private static NetworkSession session;
        private static AvailableNetworkSessionCollection availableSessions;
        public static int _SelectedSessionIndex = 0;

        private static int _MaxLocalPlayers = 1;
        private static int _MaxGamers = 8;
        private static int _PrivateGamerSlots = 2;

        public static PacketWriter _PacketWriter = new PacketWriter();
        public static PacketReader _PackerReader = new PacketReader();

        public static void CreateSession(NetworkSessionProperties oSessionProperties = null)
        {
            if (IsSessionRunning)
                EndSession();

            //NetworkSessionProperties oSessionProperties =
            //    new NetworkSessionProperties();

            //oSessionProperties[(int)SessionProperty.GameMode] = (int)GameMode.Practice;
            //oSessionProperties[(int)SessionProperty.SkillLevel] = (int)SkillLevel.Beginner;

            session = NetworkSession.Create(
                NetworkSessionType.SystemLink,
                _MaxLocalPlayers,
                _MaxGamers,
                _PrivateGamerSlots,
                null);

            session.AllowHostMigration = true;
            session.AllowJoinInProgress = true;

            session.GamerJoined += new EventHandler<GamerJoinedEventArgs>(session_GamerJoined);
            session.GamerLeft += new EventHandler<GamerLeftEventArgs>(session_GamerLeft);

            GameInfo.Debug.AddDebugMessage("Created Session");
        }

        public static void EndSession()
        {
            if (session != null)
            {
                //if(session.SessionState == NetworkSessionState.Playing)
                //    session.EndGame();

                session.Dispose();
                session = null;
                GameInfo.Debug.AddDebugMessage("Ended Session");
            }
        }

        public static void FindSessions(NetworkSessionProperties oSearchProperties = null)
        {
            if (session != null)
                return;

            //NetworkSessionProperties oSearchProperties
            //    = new NetworkSessionProperties();
            //oSearchProperties[(int)SessionProperty.GameMode] = (int)GameMode.Practice;
            //oSearchProperties[(int)SessionProperty.SkillLevel] = (int)SkillLevel.Beginner;

            availableSessions = NetworkSession.Find(
                NetworkSessionType.SystemLink,
                _MaxLocalPlayers,
                null);

            GameInfo.Debug.AddDebugMessage("Attempted to Search for Sessions");
        }

        public static void JoinSession()
        {
            if (availableSessions == null || availableSessions.Count == 0)
                return;

            session = NetworkSession.Join(availableSessions[_SelectedSessionIndex]);

            session.GamerJoined += new System.EventHandler<GamerJoinedEventArgs>(session_GamerJoined);
            session.GamerLeft += new System.EventHandler<GamerLeftEventArgs>(session_GamerLeft);
            session.GameStarted += new System.EventHandler<GameStartedEventArgs>(session_GameStarted);
            session.GameEnded += new System.EventHandler<GameEndedEventArgs>(session_GameEnded);
            session.SessionEnded += new System.EventHandler<NetworkSessionEndedEventArgs>(session_SessionEnded);
            session.HostChanged += new EventHandler<HostChangedEventArgs>(session_HostChanged);

            GameInfo.Debug.AddDebugMessage("Joined Session");
        }

        public static void WriteDataToAll(byte oMessageType, List<object> oMessages)
        {
            if (session == null)
                return;

            foreach (LocalNetworkGamer oGamer in session.LocalGamers)
            {
                _PacketWriter.Write(oMessageType);
                foreach (object oMessage in oMessages)
                {
                    if (oMessage is byte)
                        _PacketWriter.Write((byte)oMessage);
                    else if (oMessage is short)
                        _PacketWriter.Write((short)oMessage);
                    else if (oMessage is int)
                        _PacketWriter.Write((int)oMessage);
                    else if (oMessage is float)
                        _PacketWriter.Write((float)oMessage);
                }

                // Sends to everybody
                oGamer.SendData(_PacketWriter, SendDataOptions.InOrder);
            }
        }

        public static void WriteDataToHost(byte oMessageType, List<object> oMessages)
        {
            if (session == null)
                return;

            foreach (LocalNetworkGamer oGamer in session.LocalGamers)
            {
                _PacketWriter.Write(oMessageType);
                foreach (object oMessage in oMessages)
                {
                    if (oMessage is byte)
                        _PacketWriter.Write((byte)oMessage);
                    else if (oMessage is short)
                        _PacketWriter.Write((short)oMessage);
                    else if (oMessage is int)
                        _PacketWriter.Write((int)oMessage);
                    else if (oMessage is float)
                        _PacketWriter.Write((float)oMessage);
                }

                // Send it to everyone.
                oGamer.SendData(_PacketWriter, SendDataOptions.InOrder, session.Host);
            }
        }

        public static void MoveToGame()
        {
            if (session == null)
                return;

            if (session.IsEveryoneReady)
            {
                session.StartGame();

                foreach (SignedInGamer oSignedInGamer in SignedInGamer.SignedInGamers)
                {
                    //oSignedInGamer.Presence.PresenceMode = GamerPresenceMode.Winning;
                }

                GameInfo.Debug.AddDebugMessage("Moved To Game");
            }
        }

        public static void ToggleReadyLocalPlayers()
        {
            if (session == null)
                return;

            bool oSomebodyIsReady = false;

            foreach (LocalNetworkGamer gamer in session.LocalGamers)
            {
                if (gamer.IsReady)
                {
                    oSomebodyIsReady = true;
                    break;
                }
            }

            GameInfo.Debug.AddDebugMessage("Toggling Ready for Local Players");

            if (oSomebodyIsReady)
            {
                UnReadyLocalPlayers();
            }
            else
            {
                ReadyLocalPlayers();
            }
        }

        public static void ReadyLocalPlayers()
        {
            if (session == null)
                return;

            foreach (LocalNetworkGamer gamer in session.LocalGamers)
                gamer.IsReady = true;

            GameInfo.Debug.AddDebugMessage("Readied Local Players");
        }

        public static void UnReadyLocalPlayers()
        {
            if (session == null)
                return;

            foreach (LocalNetworkGamer gamer in session.LocalGamers)
                gamer.IsReady = false;

            GameInfo.Debug.AddDebugMessage("UnReadied Local Players");
        }

        public static bool IsEverybodyReady()
        {
            if (session == null)
                return false; 

            return session.IsEveryoneReady;
        }

        public static string InformationAboutCurrentSession()
        {
            //if (session == null)
            //    return "";

            if (availableSessions == null || availableSessions.Count == 0)
                return "";

            AvailableNetworkSession availableSession = availableSessions[_SelectedSessionIndex];

            string HostGamerTag = availableSession.HostGamertag;
            int GamersInSession = availableSession.CurrentGamerCount;
            int OpenPrivateGamerSlots = availableSession.OpenPrivateGamerSlots;
            int OpenPublicGamerSlots = availableSession.OpenPublicGamerSlots;

            return
                "Host: " + HostGamerTag + "\n" +
                GamersInSession + " current players" + "\n" +
                OpenPrivateGamerSlots + " private player slots" + "\n" +
                OpenPublicGamerSlots + " public player slots";
        }


        public static AvailableNetworkSessionCollection AvailableSessions
        {
            get { return availableSessions; }
        }

        public static NetworkSession Session
        {
            get { return session; }
        }

        public static bool IsSessionRunning
        {
            get { return session != null; }
        }

        public static bool IsAvailableMatchesReady
        {
            get { return availableSessions != null; }
        }


        static void session_SessionEnded(object sender, NetworkSessionEndedEventArgs e)
        {
            // Return to Main Menu
        }

        static void session_GameEnded(object sender, GameEndedEventArgs e)
        {
            // Return to Lobby Screen

            GameInfo.Debug.AddDebugMessage("Game Ended Event");
        }

        static void session_GameStarted(object sender, GameStartedEventArgs e)
        {
            // Reset everything when start a new game
            //NetworkSession session = (NetworkSession)sender;

            //for (int i = 0; i < session.AllGamers.Count; i++)
            //{
            //    //Tank tank = session.AllGamers[i].Tag as Tank;
            //    //tank.Reset(i);
            //}

            GameInfo.Debug.AddDebugMessage("Game Started Event");
        }

        static void session_GamerLeft(object sender, GamerLeftEventArgs e)
        {
            //Tank tank = e.Gamer.Tag as Tank;

            //tank.LeaveGame();

            GameInfo.Debug.AddDebugMessage("Gamer Left: " + e.Gamer.Gamertag);
        }

        static void session_GamerJoined(object sender, GamerJoinedEventArgs e)
        {
            //// Associate a tank object with this gamer.
            //e.Gamer.Tag =
            //    new Tank(Content, GraphicsDevice.PresentationParameters);

            GameInfo.Debug.AddDebugMessage("Gamer Joined: " + e.Gamer.Gamertag);
        }

        static void session_HostChanged(object sender, HostChangedEventArgs e)
        {
            //

            GameInfo.Debug.AddDebugMessage("Host Change. Old: " + e.OldHost.Gamertag + " | New: " + e.NewHost.Gamertag);
        }

    }
}
